package com.cly.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.EnumUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cly.base.contants.CacheKeysConstants;
import com.cly.course.SubjectFeign;
import com.cly.entity.Problem;
import com.cly.entity.ProblemBank;
import com.cly.entity.Subject;
import com.cly.enums.ProblemTypeEnum;
import com.cly.mapper.ProblemBankMapper;
import com.cly.result.JsonRequest;
import com.cly.result.exception.ServiceException;
import com.cly.result.exenum.RequestException;
import com.cly.service.IProblemBankService;
import com.cly.service.IProblemService;
import com.cly.vo.ProblemBankVo;
import io.seata.common.util.CollectionUtils;
import jakarta.annotation.Resource;
import lombok.RequiredArgsConstructor;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * 题库表 服务实现类
 *
 * @author by 春风能解释
 * <p>
 * 2024-06-05
 */
@Service
@RequiredArgsConstructor
public class ProblemBankServiceImpl extends ServiceImpl<ProblemBankMapper, ProblemBank> implements IProblemBankService {

    /**
     * 题库科目服务
     */
    private final SubjectFeign subjectFeign;


    /**
     * 题目服务
     */
    @Resource
    @Lazy
    private IProblemService problemService;


    /**
     * 条件查看所有题库
     *
     * @return JSON
     */
    @Override
    @Cacheable(value = CacheKeysConstants.ExamKeys.EXAM_ARRAY)
    public JsonRequest<List<ProblemBank>> lookAllProblemBank(ProblemBank problemBank) {
        return JsonRequest.success(baseMapper.lookAllProblemBank(problemBank));
    }

    /**
     * 查看题库
     *
     * @param current     页码
     * @param size        页长
     * @param problemBank 条件
     * @return JSON
     */
    @Override
    @Cacheable(value = CacheKeysConstants.ExamKeys.EXAM_ARRAY, key = "#root.args")
    public JsonRequest<List<ProblemBankVo>> lookProblemBank(Integer current, Integer size, ProblemBank problemBank) {
        IPage<ProblemBank> page = baseMapper.lookProblemBank(new Page<>(current, size), problemBank);
        List<ProblemBank> problemBankList = page.getRecords();
        List<ProblemBankVo> problemBankVos = BeanUtil.copyToList(problemBankList, ProblemBankVo.class);
        List<Long> ids = problemBankList.stream()
                .map(ProblemBank::getSubjectId)
                .toList();
        JsonRequest<Map<Long, Subject>> subjectMap = subjectFeign.lookSubjectMap(ids);
        if (subjectMap.getSuccess()) {
            Map<Long, Subject> data = subjectMap.getData();
            problemBankVos.forEach(v -> {
                v.setSubjectName(data.get(v.getSubjectId()).getName());
            });
        }
        return JsonRequest.success(problemBankVos, page.getTotal());
    }

    /**
     * 添加题库
     *
     * @param problemBank 题库
     * @return JSON
     */
    @Override
    @CacheEvict(value = {CacheKeysConstants.ExamKeys.EXAM_ARRAY, CacheKeysConstants.ExamKeys.EXAM_COUNT}, allEntries = true)
    public JsonRequest<Integer> addProblemBank(ProblemBank problemBank) {
        return JsonRequest.success(baseMapper.insert(problemBank));
    }

    /**
     * 修改题库
     *
     * @param problemBank 题库
     * @return JSON
     */
    @Override
    @CacheEvict(value = {CacheKeysConstants.ExamKeys.EXAM_ARRAY, CacheKeysConstants.ExamKeys.EXAM_COUNT}, allEntries = true)
    public JsonRequest<Integer> updateProblemBank(ProblemBank problemBank) {
        ProblemBank problemBank1 = getById(problemBank.getId());
        if (Objects.isNull(problemBank1)) {
            throw new ServiceException(RequestException.NOT_FOUND);
        }
        return JsonRequest.success(baseMapper.updateById(problemBank));
    }

    /**
     * 删除题库
     *
     * @param ids 题库id
     * @return JSON
     */
    @Override
    @CacheEvict(value = {CacheKeysConstants.ExamKeys.EXAM_ARRAY, CacheKeysConstants.ExamKeys.EXAM_COUNT}, allEntries = true)
    public JsonRequest<Integer> deleteProblemBank(List<Long> ids) {
        List<ProblemBank> problemBanks = listByIds(ids);
        if (problemBanks.isEmpty()) {
            return JsonRequest.error(RequestException.NOT_FOUND);
        }
        long count = problemService.count(Wrappers
                .lambdaQuery(Problem.class)
                .in(Problem::getBankId, ids));
        if (count > 0) {
            throw new ServiceException(RequestException.DATA_EXISTS_BINDING);
        }
        return JsonRequest.success(baseMapper.deleteByIds(ids));
    }

    /**
     * 删除题目并更新题库数据
     * <p>
     * 此方法可避免使用大量嵌套循环来遍历题目，而是使用map来存储题目，减少嵌套循环。
     * <p>
     * 最终可使用一条sql执行此操作
     *
     * @param problems 题目列表
     * @return JSON
     */
    @Override
    @CacheEvict(value = CacheKeysConstants.ExamKeys.EXAM_ARRAY, allEntries = true)
    public JsonRequest<Boolean> removeProblem(List<Problem> problems) {
        Map<Long, List<Problem>> problemBankMap = new HashMap<>();
        // 将题目根据题库分组
        for (Problem problem : problems) {
            List<Problem> value = problemBankMap.get(problem.getBankId());
            if (CollectionUtils.isEmpty(value)) {
                problemBankMap.put(problem.getBankId(), ListUtil.toList(problem));
            } else {
                value.add(problem);
                problemBankMap.put(problem.getBankId(), value);
            }
        }
        Map<Long, Integer> countMap = new HashMap<>();
        Map<Long, Integer> scoreMap = new HashMap<>();
        Map<String, Integer> typeMap = new HashMap<>();
        // 遍历题目
        problemBankMap.forEach((k, v) -> {
            // 题目数量
            Integer count = countMap.get(k);
            if (Objects.isNull(count)) {
                countMap.put(k, v.size());
            } else {
                countMap.put(k, count + v.size());
            }
            // 总分
            Integer score = scoreMap.get(k);
            if (Objects.isNull(score)) {
                scoreMap.put(k, v.stream().mapToInt(Problem::getScore).sum());
            } else {
                scoreMap.put(k, score + v.stream().mapToInt(Problem::getScore).sum());
            }
            // 题目类型
            v.forEach(problem -> {
                String key = problem.getType() +
                        "_" +
                        problem.getBankId();
                Integer type = typeMap.get(key);
                if (Objects.isNull(type)) {
                    typeMap.put(key, 1);
                } else {
                    typeMap.put(key, type + 1);
                }
            });
        });
        Set<Long> bankIds = problemBankMap.keySet();
        // 更新题库数据
        List<ProblemBank> problemBanks = new ArrayList<>();
        // 组装SQL条件
        for (Long bankId : bankIds) {
            problemBanks.add((ProblemBank) new ProblemBank()
                    .setScoreSum(scoreMap.get(bankId))
                    .setProblemNum(countMap.get(bankId))
                    .setSingleCount(typeMap.get(ProblemTypeEnum.SINGLE_CHOICE.getValue() + "_" + bankId))
                    .setMultiCount(typeMap.get(ProblemTypeEnum.MULTIPLE_CHOICE.getValue() + "_" + bankId))
                    .setJudgeCount(typeMap.get(ProblemTypeEnum.JUDGMENT.getValue() + "_" + bankId))
                    .setSubjectiveCount(typeMap.get(ProblemTypeEnum.SHORT_ANSWER.getValue() + "_" + bankId))
                    .setId(bankId));
        }
        // 批量更新
        baseMapper.updateById(problemBanks);
        return JsonRequest.success(true);
    }

    /**
     * 更新题库的分数及其个数信息
     *
     * @param problem 题目实体
     * @return JSON
     */
    @Override
    @CacheEvict(value = CacheKeysConstants.ExamKeys.EXAM_ARRAY, allEntries = true)
    public JsonRequest<Boolean> insertProblem(Problem problem) {
        Integer problemType = problem.getType();
        ProblemTypeEnum type = EnumUtil.getBy(ProblemTypeEnum.class, problemTypeEnum -> problemTypeEnum.getValue().equals(problemType));
        switch (type) {
            // 判断题
            case JUDGMENT -> update(Wrappers.lambdaUpdate(ProblemBank.class)
                    .eq(ProblemBank::getId, problem.getBankId())
                    .setIncrBy(ProblemBank::getJudgeCount, 1));// 判断题数量+1
            // 单选题
            case SINGLE_CHOICE -> update(Wrappers.lambdaUpdate(ProblemBank.class)
                    .eq(ProblemBank::getId, problem.getBankId())
                    .setIncrBy(ProblemBank::getSingleCount, 1));// 单选题数量+1
            // 多选题
            case MULTIPLE_CHOICE -> update(Wrappers.lambdaUpdate(ProblemBank.class)
                    .eq(ProblemBank::getId, problem.getBankId())
                    .setIncrBy(ProblemBank::getMultiCount, 1));// 多选题数量+1
            // 简答题
            case SHORT_ANSWER -> update(Wrappers.lambdaUpdate(ProblemBank.class)
                    .eq(ProblemBank::getId, problem.getBankId())
                    .setIncrBy(ProblemBank::getSubjectiveCount, 1));// 主观题数量+1
        }
        // 总数+1
        update(Wrappers.lambdaUpdate(ProblemBank.class)
                .eq(ProblemBank::getId, problem.getBankId())
                .setIncrBy(ProblemBank::getProblemNum, 1)
                .setIncrBy(ProblemBank::getScoreSum, problem.getScore()));
        return JsonRequest.success(true);
    }
}




